﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
//
using PerceptiveMCAPI.Types;
//
namespace PerceptiveMCAPI
{
   internal static class Validator
   {
      // --------------------- message formatter
      internal static Api_ValidatorMessage FormatMsg( EnumValues.MessageLevel msg_level, string msg_property, string msg_text )
      {
         Api_ValidatorMessage val = new Api_ValidatorMessage
         {
            MessageLevel = msg_level,
            PropertyName = msg_property,
            MessageText = msg_text
         };
         return val;
      }

      #region ------------------------------------------------------------------------- Multi-Use

      // apikey 
      internal static Api_ValidatorMessage apikey_valid( string apikey )
      {
         // TODO: ?? validate format of apikey
         if ( string.IsNullOrEmpty( apikey ) )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, "apikey", "apikey was not specified, or has an invalid format." );
         }
         return null;
      }
      // cid
      internal static Api_ValidatorMessage cid_valid( string cid )
      {
         // TODO: ?? validate format of cid
         if ( string.IsNullOrEmpty( cid ) )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, "cid", "Campaign Id, 'cid', was not specified, or has an invalid format." );
         }
         return null;
      }
      // id (listId)
      internal static Api_ValidatorMessage ListId_valid( string id )
      {
         // TODO: ?? validate format of id
         if ( string.IsNullOrEmpty( id ) )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, "id", "List Id, 'id', was not specified, or has an invalid format." );
         }
         return null;
      }
      // email
      internal static Api_ValidatorMessage email_valid( string email )
      {
         if ( string.IsNullOrEmpty( email ) )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, "email", "An email address is required and was not provided." );
         }
         //
         if ( !EnumValues.rexEmail.IsMatch( email ) )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, "email", string.Format( "The email address: [{0}] is not properly formed.", email ) );
         }
         //
         return null;
      }
      // email_type_valid
      internal static Api_ValidatorMessage email_type_valid( EnumValues.emailType emailType )
      {
         if ( emailType == EnumValues.emailType.NotSpecified )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, "email_type", "The 'email_type' was not specified." );
         }
         return null;
      }
      // url_valid
      internal static Api_ValidatorMessage url_valid( string url )
      {
         if ( string.IsNullOrEmpty( url ) )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, "url", "'url' is required and was not provided." );
         }

         try
         {
            // if url doesn't contain :// specified, prefix it before the test so the uri works
            // webhooks allows a url w/o the protocol 
            string t_Url = url.Trim();
            if ( !t_Url.Contains( "://" ) ) t_Url = string.Concat( "http://", t_Url );

            Uri address = new Uri( t_Url );
            if ( address.Scheme != Uri.UriSchemeHttp && address.Scheme != Uri.UriSchemeHttps )
               return FormatMsg( EnumValues.MessageLevel.Error, "url",
                  string.Format( "The url: '{0}' is not properly formed.", url ) );
            if ( address.HostNameType != UriHostNameType.Dns )
               return FormatMsg( EnumValues.MessageLevel.Error, "url",
                  string.Format( "The url: '{0}' is not properly formed.", url ) );
            //
            if ( !EnumValues.rexUrl.IsMatch( t_Url ) )
            {
               return FormatMsg( EnumValues.MessageLevel.Error, "url",
                  string.Format( "The url: '{0}' is not properly formed.", url ) );
            }
            //            
            return null;
         }
         catch ( Exception ex )
         {
            if ( ex.InnerException != null ) ex = ex.InnerException;
            return FormatMsg( EnumValues.MessageLevel.Error, "url",
               string.Format( "The url: '{0}' is not properly formed. {1}", url, ex.Message ) );
         }
      }
      // url_working
      internal static Api_ValidatorMessage url_working( string url )
      {
         // check valid before trying to find it
         Api_ValidatorMessage url_valid_msg = url_valid( url );
         if ( url_valid_msg != null ) return url_valid_msg;

         // if url doesn't contain :// prefix it before the test so the url works
         // webhooks allows a url w/o the protocol 
         string t_Url = url.Trim();
         if ( !t_Url.Contains( "://" ) ) t_Url = string.Concat( "http://", t_Url );
         HttpWebRequest request = (HttpWebRequest)WebRequest.Create( t_Url );
         HttpWebResponse response = null;
         int code = 0;

         try
         {
            response = (HttpWebResponse)request.GetResponse();
            int.TryParse( response.StatusCode.ToString(), out code );
            if ( code > 299 ) throw new ApplicationException( string.Format( "Http response code: {0}", code ) );
         }
         catch ( Exception ex )
         {
            if ( ex.InnerException != null ) ex = ex.InnerException;
            return FormatMsg( EnumValues.MessageLevel.Error, "url",
               string.Format( "The call to url: '{0}' returned in error. {1}", url, ex.Message ) );
         }
         //            
         return null;
      }
      // since
      internal static Api_ValidatorMessage since_valid( DateTime since )
      {
         if ( since > DateTime.UtcNow )
         {
            return FormatMsg( EnumValues.MessageLevel.Warning, "since", "'since' date/time cannot be in the future. All times are UTC." );
         }
         return null;
      }
      // start
      internal static Api_ValidatorMessage start_valid( int start )
      {
         if ( start < 0 )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, "start",
               "'start' must be an integer greater than or equal to 0" );
         }
         return null;
      }
      // limit
      internal static Api_ValidatorMessage limit_valid( int limit, int maxLimit )
      {
         if ( limit < 1 || limit > maxLimit )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, "limit",
             string.Format( "'limit' must be greater than 0 and less than the maximum of {0:N0}.", maxLimit ) );
         }
         return null;
      }
      // merge_vars
      internal static Api_ValidatorMessage merge_vars_valid( Dictionary<string, object> merge_vars )
      {
         // Merge_vars aren't required for sub, upd -- so existence error isn't an issue
         // blank values are valid -- they clear out values, so what to edit?
         // warning if none entered?
         // can only validate required if I grab the existing MVs and do a check, 
         //       which is not a plain wrapper -- it's more admin
         //
         // Hmmm... need to ponder.

         if ( merge_vars.Count == 0 )
         {
            return FormatMsg( EnumValues.MessageLevel.Warning, "merge_vars", "No 'merge_vars' were provided." );
         }
         return null;
      }
      // Not implemented 
      internal static Api_ValidatorMessage api_NotImplemented( string api_Method )
      {
         return FormatMsg( EnumValues.MessageLevel.Terminal, EnumValues.valNoProperty,
            string.Format( "Method '{0}' is not currently implemented", api_Method ) );
      }
      // Deprecated
      internal static Api_ValidatorMessage deprecated( string api_Method )
      {
         return FormatMsg( EnumValues.MessageLevel.Warning, EnumValues.valNoProperty,
          string.Format( "Method '{0}' has been deprecated. It is suggested that an alternate method is used.", api_Method ) );
      }

      #endregion

      #region --------------------------------- Generic existence, type checks

      // check for empty string
      internal static Api_ValidatorMessage string_value_required( string value, string parmName )
      {
         if ( string.IsNullOrEmpty( value ) )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, parmName,
               string.Format( "Required parameter '{0}' was not specified.", parmName ) );
         }
         return null;
      }
      // check for positive integer
      internal static Api_ValidatorMessage int_value_required( int value, string parmName )
      {
         if ( value < 1 )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, parmName,
               string.Format( "Integer value '{0}' must be greater than 0.", parmName ) );
         }
         return null;
      }
      // check of type
      internal static Api_ValidatorMessage parameter_type_valid( string name, string type, object parm )
      {
         string parm_type = parm.GetType().Name;
         if ( parm_type.ToLower() != type.ToLower() )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, name,
               string.Format( "Parameter '{0}' type is {1}. Type of {2} was expected.", name, parm_type, type ) );
         }
         return null;
      }

      // check collection has entries
      internal static Api_ValidatorMessage collection_has_entries( ICollection value, string parmName )
      {
         if ( value == null && value.Count == 0 )
         {
            return FormatMsg( EnumValues.MessageLevel.Error, parmName,
               string.Format( "Collection '{0}' is null or empty.", parmName ) );
         }
         return null;
      }


      #endregion

   }
}
